package mirrormonkey.rpc.member;

import java.lang.reflect.Method;

import mirrormonkey.framework.SyncAppState;
import mirrormonkey.framework.annotations.IdentityAware;
import mirrormonkey.framework.entity.StaticEntityDataIR;
import mirrormonkey.framework.member.MemberDataIR;
import mirrormonkey.framework.member.StaticMemberData;
import mirrormonkey.rpc.annotations.InvokeLocally;
import mirrormonkey.rpc.annotations.InvokeLocally.LocalInvokeMode;
import mirrormonkey.rpc.annotations.ReceiveRpcFrom;
import mirrormonkey.rpc.annotations.RpcTarget;
import mirrormonkey.rpc.member.RpcMethodData.RpcMethodKey;
import mirrormonkey.util.annotations.hfilter.ClassFilter;
import mirrormonkey.util.annotations.parsing.AnnotationParser;
import mirrormonkey.util.annotations.parsing.MethodIR;

public class RpcMethodDataIR extends MethodIR implements MemberDataIR {

	protected final RpcMethodKey memberKey;

	public RpcMethodDataIR(AnnotationParser parser, Method member) {
		super(parser, member);
		memberKey = new RpcMethodKey(member.getName(),
				member.getParameterTypes());
		addCollectType(RpcTarget.class);
		addCollectType(ReceiveRpcFrom.class);
		addCollectType(InvokeLocally.class);
		addCollectType(IdentityAware.class);
	}

	public RpcMethodDataIR(RpcMethodDataIR previous, Method member) {
		super(previous, member);
		this.memberKey = previous.memberKey;
	}

	@Override
	public int compareTo(MemberDataIR o) {
		if (getSortingOrder() != o.getSortingOrder()) {
			return Integer.valueOf(getSortingOrder()).compareTo(
					Integer.valueOf(o.getSortingOrder()));
		}
		RpcMethodDataIR other = (RpcMethodDataIR) o;
		int comp = memberKey.name.compareTo(memberKey.name);
		if (comp != 0) {
			return comp;
		}
		if (memberKey.argTypes.length != other.memberKey.argTypes.length) {
			return memberKey.argTypes.length - other.memberKey.argTypes.length;
		}
		for (int i = 0; i < memberKey.argTypes.length; i++) {
			comp = memberKey.argTypes[i].getName().compareTo(
					other.memberKey.argTypes[i].getName());
			if (comp != 0) {
				return comp;
			}
		}
		return 0;
	}

	@Override
	public boolean equals(Object o) {
		if (!RpcMethodDataIR.class.isInstance(o)) {
			return false;
		}
		RpcMethodDataIR other = (RpcMethodDataIR) o;
		return memberKey.equals(other.memberKey);
	}

	@Override
	public StaticMemberData extractData(int id,
			StaticEntityDataIR staticEntityDataIR, SyncAppState appState,
			MemberDataIR connectedMemberIR) {
		RpcTarget annotation = getCollectedAnnotation(RpcTarget.class);
		ReceiveRpcFrom receiveFrom = getCollectedAnnotation(ReceiveRpcFrom.class);

		boolean allowInbound = ClassFilter.Eval.contains(receiveFrom.value(),
				staticEntityDataIR.connectedClass);

		InvokeLocally local = getCollectedAnnotation(InvokeLocally.class);
		LocalInvokeMode localInvokeMode = local == null ? mirrormonkey.rpc.annotations.InvokeLocally.LocalInvokeMode.NONE
				: local.value();

		return new RpcMethodData(
				id,
				getCollectedMethod(),
				appState.entityProvider
						.getInterpreters(getParameterAnnotations()),
				appState.entityProvider
						.getInterpreter(getCollectedAnnotation(IdentityAware.class)),
				memberKey, localInvokeMode.equals(LocalInvokeMode.BEFORE),
				localInvokeMode.equals(LocalInvokeMode.AFTER), annotation
						.reliable(), allowInbound,
				annotation.responseTimeout(), annotation.callTimeout());
	}

	@Override
	public int getSortingOrder() {
		return 100;
	}

}
